package com.gaussian.property.app.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gaussian.property.app.vo.*;
import com.gaussian.property.module.biz.entity.*;
import com.gaussian.property.module.biz.enums.Period;
import com.gaussian.property.module.biz.mapper.*;
import com.gaussian.property.module.biz.service.*;
import com.gaussian.property.module.biz.service.impl.AbstractCheckTableServiceImpl;
import com.gaussian.property.module.biz.vo.check.CheckStandardScoreQueryCondition;
import com.gaussian.property.module.biz.vo.check.ProjectCheckStandardScoreDto;
import com.songqi.common.core.constant.Constants;
import com.songqi.common.core.exception.CustomException;
import com.songqi.common.core.utils.BeanCopyUtil;
import com.songqi.common.mybatis.core.query.LambdaQueryWrapperX;
import com.songqi.common.security.utils.SecurityUtils;

import lombok.Data;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: songqi(13776346982)
 * @date: 2024/4/9 23:51
 */
@Service
public class CheckService extends AbstractCheckTableServiceImpl<CheckTableMapper, CheckTable> {


    @Resource
    private ProjectCheckTableMapper projectCheckTableMapper;
    @Resource
    private IProjectCheckTableService iProjectCheckTableService;
    @Resource
    private ProjectCheckStandardScoreMapper projectCheckStandardScoreMapper;
    @Resource
    private CheckCriteriaMapper checkCriteriaMapper;
    @Resource
    private ICheckModuleService iCheckModuleService;
    @Resource
    private ICheckCriteriaService iCheckCriteriaService;
    @Resource
    private ICheckStandardService iCheckStandardService;
    @Resource
    private IProjectCheckRecordService iProjectCheckRecordService;
    @Resource
    private IProjectCheckStandardScoreService iProjectCheckStandardScoreService;
    @Resource
    private IProjectCheckStandardScoreImageService iProjectCheckStandardScoreImageService;
    @Resource
    private IProjectCheckRecordImageService iProjectCheckRecordImageService;
    @Resource
    private ITempProjectCheckRecordService iTempProjectCheckRecordService;
    @Resource
    private ITempCheckItemService iTempCheckItemService;
    @Resource
    private ITempCheckItemImageService iTempCheckItemImageService;
    @Resource
    private CheckModuleMapper checkModuleMapper;
    @Resource
    private IAppUserService iAppUserService;
    @Resource
    private IAppUserRoleService iAppUserRoleService;
    @Resource
    private IProjectCheckTableRoleService iProjectCheckTableRoleService;


    /**
     * 根据项目id查询项目配置的稽核表
     * @param projectId
     * @return
     */
    public List<CheckTableVo> queryConfigCheckTable(String projectId) {
        List<CheckTable> checkTables = projectCheckTableMapper.queryProjectCheckTable(projectId);
        if(CollectionUtil.isEmpty(checkTables)){
            throw new CustomException("该项目未配置稽核表，请联系系统管理员");
        }
        return BeanCopyUtil.copyList(checkTables, CheckTableVo.class);
    }




    /**
     * 查询稽核表详细信息和表中稽核标准的今日稽核数据
     * @param checkTableId
     * @return
     */
    public CheckTableDetailVo queryCheckTableDetail(String projectId, String checkTableId, String searchKey) {
        CheckTable checkTable = super.getById(checkTableId);
        if(checkTable == null){
            throw new CustomException("该稽核表id不存在");
        }
        //查询项目的稽核表
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(projectId, checkTableId);
        CheckTableDetailVo checkTableDetail = new CheckTableDetailVo();

        List<CheckStandard> checkStandardList = queryCheckStandardListByStandardName(searchKey, checkTableId);
        if(CollectionUtil.isNotEmpty(checkStandardList)){
            List<CheckStandardVo> checkStandardVoList = BeanCopyUtil.copyList(checkStandardList, CheckStandardVo.class);
            LocalDateTime endTime = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
            LocalDateTime startTime = LocalDateTime.of(LocalDate.now().minusDays(7L), LocalTime.MIN);
            for(CheckStandardVo checkStandardVo : checkStandardVoList){
                //查询近7日得分：稽核评分相加/次数
                Double sumDeductionInLast7Days = projectCheckStandardScoreMapper.sumStandardDeduction(projectCheckTable.getProjectId(), projectCheckTable.getCheckTableId(), checkStandardVo.getCheckStandardId(), startTime, endTime);
                if(sumDeductionInLast7Days != null){
                    // 统计一段时间内项目的稽核表稽核次数
//                    long checkCount = countProjectCheckRecord(projectId, checkTableId, startTime, endTime);
                    long last7DayCheckDays = countProjectCheckDays(projectId, checkTableId, startTime, endTime);
                    if(last7DayCheckDays > 0){
                        checkStandardVo.setAvgScoreInLast7Days(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumDeductionInLast7Days, new BigDecimal(last7DayCheckDays), 1)));
                    }
                }
                // 查询标准id今天稽核得分
//                ProjectCheckStandardScore todayProjectCheckStandardScore = queryTodayProjectCheckStandardScore(projectId, checkTableId, checkStandardVo.getCheckStandardId());
//                if(todayProjectCheckStandardScore != null){
//                    checkStandardVo.setDeduction(todayProjectCheckStandardScore.getDeduction());
//                }
            }
            List<CheckModuleVo> checkModuleVoList = convert2CheckModuleVoList(checkStandardVoList);
            checkTableDetail.setCheckModuleVoList(checkModuleVoList);
        }
        //查询稽核记录时上传的图片和备注
        List<CheckTableDetailVo.CheckRecordVo> checkRecordVoList = queryTodayCheckRecord(projectId, checkTableId);
        checkTableDetail.setCheckRecordVoList(checkRecordVoList);
        return checkTableDetail;
    }







    /**
     * 判断项目是否允许稽核
     * @param projectCheckTable
     * @param appUser
     * @return
     */
    public void canStartCheck(ProjectCheckTable projectCheckTable, AppUser appUser) {
        if(projectCheckTable != null){
            if(projectCheckTable.getStatus().equals(Constants.DISABLE)){
                throw new CustomException("当前项目配置表已停用，不能稽核");
            }
            // 判断当前用户的角色是否允许操作该稽核表
            if (checkAppUserRoleInAllowedRoleList(appUser, projectCheckTable)) {
                String checkPeriod = projectCheckTable.getCheckPeriod();
                Integer countPerPeriod = projectCheckTable.getCountPerPeriod();
                LocalDateTime queryStartTime = null;
                LocalDateTime queryEndTime = null;
                // 获取当前日期
                LocalDate currentDate = LocalDate.now();
                if(Period.daily.getName().equals(checkPeriod)){
                    queryStartTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
                    queryEndTime = LocalDateTime.now();
                }else if(Period.weekly.getName().equals(checkPeriod)){
                    // 获取当前日期所在周的第一天
                    LocalDate firstDayOfWeek = currentDate.with(DayOfWeek.MONDAY);
                    queryStartTime = LocalDateTime.of(firstDayOfWeek, LocalTime.MIN);
                    queryEndTime = LocalDateTime.now();
                }else if(Period.monthly.getName().equals(checkPeriod)){
                    // 获取当前月的第一天
                    LocalDate firstDayOfMonth = currentDate.withDayOfMonth(1);
                    queryStartTime = LocalDateTime.of(firstDayOfMonth, LocalTime.MIN);
                    queryEndTime = LocalDateTime.now();
                }
                Long checkCount = queryPeriodCheckCount(queryStartTime, queryEndTime, projectCheckTable.getProjectId(), projectCheckTable.getCheckTableId());
                if (countPerPeriod <= checkCount){
                    throw new CustomException("该项目已经超过允许的稽核次数，无法进行稽核");
                }
            }else {
                throw new CustomException("当前角色不能操作该稽核表");
            }
        }


    }



    /**
     * 获取临时稽核记录id。用来保存前端二级页面提交的数据。
     * @param projectId
     * @param checkTableId
     * @return
     */
    public String queryTempProjectCheckRecordId(String projectId, String checkTableId) {
        AppUser appUser = (AppUser) SecurityUtils.getTokenUser();
        // 先判断用户是否已有临时稽核记录id
       /* LambdaQueryWrapper<TempProjectCheckRecord> queryWrapper = new LambdaQueryWrapper<TempProjectCheckRecord>()
                .eq(TempProjectCheckRecord::getProjectId, projectId)
                .eq(TempProjectCheckRecord::getCheckTableId, checkTableId)
                .eq(TempProjectCheckRecord::getAppUserId, appUser.getAppUserId());
        TempProjectCheckRecord tempProjectCheckRecord = iTempProjectCheckRecordService.getOne(queryWrapper);
        if(tempProjectCheckRecord == null){
            tempProjectCheckRecord = new TempProjectCheckRecord();
            tempProjectCheckRecord.setCheckTableId(checkTableId);
            tempProjectCheckRecord.setProjectId(projectId);
            tempProjectCheckRecord.setAppUserId(appUser.getAppUserId());
            iTempProjectCheckRecordService.save(tempProjectCheckRecord);
        }*/
        TempProjectCheckRecord tempProjectCheckRecord = new TempProjectCheckRecord();
        tempProjectCheckRecord.setCheckTableId(checkTableId);
        tempProjectCheckRecord.setProjectId(projectId);
        tempProjectCheckRecord.setAppUserId(appUser.getAppUserId());
        iTempProjectCheckRecordService.save(tempProjectCheckRecord);
        return tempProjectCheckRecord.getTempProjectCheckRecordId();
    }

    /**
     * 获取前端二级页面临时提交的打分数据
     * @param tempProjectCheckRecordId
     * @param checkStandardId
     * @return
     */
    public CheckItem queryTempCheckItem(String tempProjectCheckRecordId, String checkStandardId) {
        LambdaQueryWrapper<TempCheckItem> queryWrapper = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempProjectCheckRecordId)
                .eq(TempCheckItem::getCheckStandardId, checkStandardId);
        TempCheckItem tempCheckItem = iTempCheckItemService.getOne(queryWrapper);
        if(tempCheckItem != null){
            CheckItem checkItem = BeanCopyUtil.copyProperties(tempCheckItem, CheckItem.class);
            checkItem.setImagePathList(queryTempImageUrlList(tempCheckItem.getTempCheckItemId()));
            return checkItem;
        }
        return null;
    }

    /**
     * 临时保存前端二级页面提交的打分数据
     * @param tempCheckItemForm
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveTempCheckItem(TempCheckItemForm tempCheckItemForm) {
        TempProjectCheckRecord tempProjectCheckRecord = iTempProjectCheckRecordService.getById(tempCheckItemForm.getTempProjectCheckRecordId());
        if(tempProjectCheckRecord == null){
            throw new CustomException("参数错误。临时稽核记录id不存在，请先调用[获取临时稽核记录id]接口");
        }
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(tempProjectCheckRecord.getProjectId(), tempProjectCheckRecord.getCheckTableId());
        //判断数据是否符合规则
        CheckStandard checkStandard = iCheckStandardService.getById(tempCheckItemForm.getCheckStandardId());
        if(checkStandard == null){
            throw new CustomException("审核标准ID不存在");
        }
        // 前端传过来的得分
        Double deduction = tempCheckItemForm.getDeduction();
        // 查询标准所在的指标
        CheckCriteria checkCriteria = checkCriteriaMapper.queryCheckCriteriaByStandardId(checkStandard.getCheckStandardId());
        // 查询标准所在模块
        CheckModule checkModule = checkModuleMapper.queryCheckModuleByStandardId(checkStandard.getCheckStandardId());
        if(checkModule.getIsAllowAttach().equals(Constants.YES) && CollectionUtil.isEmpty(tempCheckItemForm.getImagePathList())){
            throw new CustomException("此模块要求必传图片");
        }
        // 清除上一次临时提交上来的数据
        LambdaQueryWrapper<TempCheckItem> queryWrapper = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempCheckItemForm.getTempProjectCheckRecordId())
                .eq(TempCheckItem::getCheckStandardId, tempCheckItemForm.getCheckStandardId());
        iTempCheckItemService.remove(queryWrapper);

        // 验证前端临时打分是否符合打分规则
        validateTempSingleCheckStandardDeduction(tempCheckItemForm.getTempProjectCheckRecordId(),
                projectCheckTable.getProjectCheckTableId(),
                checkModule, checkCriteria, checkStandard, deduction);

        TempCheckItem tempCheckItem = new TempCheckItem();
        BeanCopyUtil.copyProperties(tempCheckItemForm, tempCheckItem);
        tempCheckItem.setCheckCriteriaId(checkCriteria.getCheckCriteriaId());
        tempCheckItem.setCheckModuleId(checkModule.getCheckModuleId());
        iTempCheckItemService.save(tempCheckItem);
        if(CollectionUtil.isNotEmpty(tempCheckItemForm.getImagePathList())){
            for(String imageUrl : tempCheckItemForm.getImagePathList()){
                TempCheckItemImage tempCheckItemImage = new TempCheckItemImage();
                tempCheckItemImage.setImagePath(imageUrl);
                tempCheckItemImage.setTempCheckItemId(tempCheckItem.getTempCheckItemId());
                tempCheckItemImage.setTempProjectCheckRecordId(tempCheckItemForm.getTempProjectCheckRecordId());
                iTempCheckItemImageService.save(tempCheckItemImage);
            }
        }
    }



    /**
     * 判断当前用户是否允许操作该项目稽核表。
     * @param appUser
     * @param projectCheckTable
     * @return true-允许；false-不允许
     */
    private boolean checkAppUserRoleInAllowedRoleList(AppUser appUser, ProjectCheckTable projectCheckTable) {
        LambdaQueryWrapper<AppUserRole> queryWrapper = new LambdaQueryWrapper<AppUserRole>()
                .eq(AppUserRole::getAppUserId, appUser.getAppUserId());
        List<AppUserRole> appUserRoleList = iAppUserRoleService.list(queryWrapper);
        if(CollectionUtil.isEmpty(appUserRoleList)){
            throw new CustomException("当前用户未配置角色。请联系高仙后台管理员");
        }
        List<String> appUserRoleIdList = appUserRoleList.stream().map(AppUserRole::getOptRoleId).collect(Collectors.toList());
        List<String> optRoleIdList = queryProjectCheckTableOptRoleId(projectCheckTable.getProjectCheckTableId());
        if(CollectionUtil.isNotEmpty(optRoleIdList)){
            boolean isAllowOptRole = false;
            for(String optRoleId : optRoleIdList){
                if(appUserRoleIdList.contains(optRoleId)){
                    isAllowOptRole = true;
                    break;
                }
            }
            return isAllowOptRole;
        }
        return true;
    }


    /**
     * 查询项目稽核表绑定的操作角色id列表
     * @param projectCheckTableId
     * @return
     */
    private List<String> queryProjectCheckTableOptRoleId(String projectCheckTableId) {
        LambdaQueryWrapper<ProjectCheckTableRole> queryWrapper = new LambdaQueryWrapper<ProjectCheckTableRole>()
                .eq(ProjectCheckTableRole::getProjectCheckTableId, projectCheckTableId);
        List<ProjectCheckTableRole> list = iProjectCheckTableRoleService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().map(ProjectCheckTableRole::getOptRoleId).collect(Collectors.toList());
        }
        return null;
    }



    /**
     * 验证前端临时提交的打分记录是否符合打分规则
     * @param tempProjectCheckRecordId
     * @param projectCheckTableId
     * @param checkModule
     * @param checkCriteria
     * @param checkStandard
     * @param deduction
     */
    private void validateTempSingleCheckStandardDeduction(String tempProjectCheckRecordId,
                                                          String projectCheckTableId,
                                                          CheckModule checkModule,
                                                          CheckCriteria checkCriteria,
                                                          CheckStandard checkStandard,
                                                          Double deduction) {

        ThresholdScore thresholdScore = getThresholdScore(checkModule, checkCriteria, checkStandard, deduction);

        // 查询该标准今天所有临时已提交的标准的得分和
        Double sumTodayTempStandardDeduction = sumTodayTempStandardDeduction(tempProjectCheckRecordId, checkStandard.getCheckStandardId());
        // 查询该标准今天所有已提交的标准的得分和
        Double sumTodayStandardDeduction = sumTodayStandardDeduction(projectCheckTableId, checkStandard.getCheckStandardId());
        // 判断标准的总得分值是否大于标准分值
//        validateDeduction(deduction, thresholdScore.standardScore, "得分不能大于标准分值");
        validateDeduction(sumTodayTempStandardDeduction + sumTodayStandardDeduction, deduction, thresholdScore.standardScore, "得分不能大于标准分值");

        // 查询该标准所在指标今天临时所有已提交的标准的得分和
        Double sumTodayTempStandardDeductionUnderCriteria = sumTodayTempStandardDeductionUnderCriteria(tempProjectCheckRecordId, checkCriteria.getCheckCriteriaId());
        // 查询该标准所在指标今天所有已提交的标准的得分和
        Double sumTodayStandardDeductionUnderCriteria = sumTodayStandardDeductionUnderCriteria(projectCheckTableId, checkCriteria.getCheckCriteriaId());
        // 判断标准的总得分值是否大于指标分值
//        validateDeduction(deduction, thresholdScore.criteriaScore, "标准的总扣分值不能大于指标分值");
        validateDeduction(sumTodayTempStandardDeductionUnderCriteria + sumTodayStandardDeductionUnderCriteria, deduction, thresholdScore.criteriaScore, "标准的总扣分值不能大于指标分值");

        // 查询该标准所在模块今天临时所有已提交的标准的得分和
        Double sumTodayTempStandardDeductionUnderModule = sumTodayTempStandardDeductionUnderModule(tempProjectCheckRecordId, checkModule.getCheckModuleId());
        Double sumTodayStandardDeductionUnderModule = sumTodayStandardDeductionUnderModule(projectCheckTableId, checkModule.getCheckModuleId());
        // 判断标准的总得分值是否大于模块分值
//        validateDeduction(deduction, thresholdScore.checkModuleScore, "标准的总扣分值不能大于模块分值");
        validateDeduction(sumTodayTempStandardDeductionUnderModule + sumTodayStandardDeductionUnderModule, deduction, thresholdScore.checkModuleScore, "标准的总扣分值不能大于模块分值");
    }





    /**
     * 验证前端提交的打分记录是否符合打分规则
     * @param projectCheckTableId
     * @param checkModule
     * @param checkCriteria
     * @param checkStandard
     * @param deduction
     */
    private void validateSubmitCheckStandardDeduction(String projectCheckTableId,
                                                      CheckModule checkModule,
                                                      CheckCriteria checkCriteria,
                                                      CheckStandard checkStandard,
                                                      Double deduction) {

        ThresholdScore thresholdScore = getThresholdScore(checkModule, checkCriteria, checkStandard, deduction);

        // 查询该标准今天所有已提交的标准的得分和
        Double sumTodayStandardDeduction = sumTodayStandardDeduction(projectCheckTableId, checkStandard.getCheckStandardId());
        // 判断标准的总得分值是否大于标准分值
        validateDeduction(sumTodayStandardDeduction, deduction, thresholdScore.standardScore, "得分不能大于标准分值");
//        validateDeduction(deduction, thresholdScore.standardScore, "得分不能大于标准分值");

        // 查询该标准所在指标今天所有已提交的标准的得分和
        Double sumTodayStandardDeductionUnderCriteria = sumTodayStandardDeductionUnderCriteria(projectCheckTableId, checkCriteria.getCheckCriteriaId());
        // 判断标准的总得分值是否大于指标分值
        validateDeduction(sumTodayStandardDeductionUnderCriteria + deduction, thresholdScore.criteriaScore, "标准的总扣分值不能大于指标分值");
//        validateDeduction(deduction, thresholdScore.criteriaScore, "标准的总扣分值不能大于指标分值");

        // 查询该标准所在模块今天所有已提交的标准的得分和
        Double sumTodayStandardDeductionUnderModule = sumTodayStandardDeductionUnderModule(projectCheckTableId, checkModule.getCheckModuleId());
        // 判断标准的总得分值是否大于模块分值
        validateDeduction(sumTodayStandardDeductionUnderModule + deduction, thresholdScore.checkModuleScore, "标准的总扣分值不能大于模块分值");
//        validateDeduction(deduction, thresholdScore.checkModuleScore, "标准的总扣分值不能大于模块分值");
    }

    /**
     * 保存用户提交的稽核记录
     * @param checkForm
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveCheck(CheckForm checkForm, AppUser appUser) {
        //查询项目的稽核表
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(checkForm.getProjectId(), checkForm.getCheckTableId());
        if(projectCheckTable == null){
            throw new CustomException("参数值不正确");
        }
        canStartCheck(projectCheckTable, appUser);
        //将打分标准按 模块（module）-> 指标（criteria）-> 标准（standard）层次组装好，方便计算扣分值有没有超过总分值限制
        List<CheckModuleDetail> checkModuleDetailList = convert2CheckModuleDetailList(checkForm.getCheckItemList());
        // 验证稽核标准中的扣分值是否合格
        validateCheckStandardDeduction(projectCheckTable.getProjectCheckTableId(), checkModuleDetailList);

        // 保存项目稽核记录
        ProjectCheckRecord projectCheckRecord = saveProjectCheckRecord(checkForm, projectCheckTable.getProjectCheckTableId());
        // 保存稽核标准的扣分值
        saveProjectCheckStandardScore(checkForm, projectCheckRecord);
    }


    /**
     * 清除临时数据
     * @param tempProjectCheckRecordId
     */
    @Async("threadPoolTaskExecutor")
    @Transactional(rollbackFor = Exception.class)
    public void cleanTempProjectCheckRecord(String tempProjectCheckRecordId) {
        LambdaQueryWrapper<TempCheckItemImage> queryWrapper = new LambdaQueryWrapper<TempCheckItemImage>()
                .eq(TempCheckItemImage::getTempProjectCheckRecordId, tempProjectCheckRecordId);
        iTempCheckItemImageService.remove(queryWrapper);

        LambdaQueryWrapper<TempCheckItem> queryWrapper2 = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempProjectCheckRecordId);
        iTempCheckItemService.remove(queryWrapper2);
        iTempProjectCheckRecordService.removeById(tempProjectCheckRecordId);
    }


    /**
     * 查询某个模块下的标准在一定时间范围内的评分记录
     * @param projectId
     * @param checkTableId
     * @param checkModuleId
     * @param range
     * @return
     */
    public CheckStandardScoreStatistic queryCheckStandardScoreStatistic(String projectId,
                                                                        String checkTableId,
                                                                        String checkModuleId,
                                                                        String range) {
        DateTimeRange dateTimeRange = getDateTimeRange(range);
        LocalDateTime startTime = dateTimeRange.startTime;
        LocalDateTime endTime = dateTimeRange.endTime;
        if("today".equals(range)){
            CheckStandardScoreStatistic checkStandardScoreStatistic = new CheckStandardScoreStatistic();
            ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(projectId, checkTableId);
            if(projectCheckTable == null){
                throw new CustomException("【参数错误】未找到项目与稽核标准的绑定关系");
            }
            checkStandardScoreStatistic.setPassingScore(projectCheckTable.getPassingScore());
            List<CheckStandardScoreVo> checkStandardScoreVoList = new ArrayList<>();
            CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
            queryCondition.setProjectId(projectId);
            queryCondition.setCheckTableId(checkTableId);
            queryCondition.setCheckModuleId(checkModuleId);
            queryCondition.setStartTime(startTime);
            queryCondition.setEndTime(endTime);
            queryCondition.setOrderBy("d.sort_num asc");
            //查询出标准的扣分明细
            List<ProjectCheckStandardScoreDto> checkStandardScoreDtoList = projectCheckStandardScoreMapper.queryValidStandardScore(queryCondition);
            if(CollectionUtil.isNotEmpty(checkStandardScoreDtoList)){
                // 排序
                LinkedHashMap<String, List<ProjectCheckStandardScoreDto>> checkStandardScoreMap = checkStandardScoreDtoList.stream()
                        .sorted(Comparator.comparing(ProjectCheckStandardScoreDto::getStandardSortNum))
                        .collect(Collectors.groupingBy(ProjectCheckStandardScoreDto::getCheckStandardId, LinkedHashMap::new, Collectors.toList()));
                for (Map.Entry<String, List<ProjectCheckStandardScoreDto>> entry : checkStandardScoreMap.entrySet()) {
                    List<ProjectCheckStandardScoreDto> checkStandardScoreList = entry.getValue();
                    ProjectCheckStandardScoreDto checkStandardScoreDto = checkStandardScoreList.get(0);
                    CheckStandardScoreVo checkStandardScoreVo = BeanCopyUtil.copyProperties(checkStandardScoreDto, CheckStandardScoreVo.class);

                    double sumCriteriaDeduction = projectCheckStandardScoreMapper.sumCriteriaDeduction(projectId, checkTableId, checkStandardScoreDto.getCheckCriteriaId(), startTime, endTime);
                    double sumStandardDeduction = checkStandardScoreList.stream().mapToDouble(ProjectCheckStandardScoreDto::getDeduction).sum();
                    // 统计区间内有稽核的天数
                    long checkDays = countProjectCheckDays(projectId, checkTableId, startTime, endTime);
                    if(checkDays > 0){
                        checkStandardScoreVo.setDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumStandardDeduction, new BigDecimal(checkDays), 1)));
                        checkStandardScoreVo.setCriteriaDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumCriteriaDeduction, new BigDecimal(checkDays), 1)));
                    }
                    LocalDateTime endTime2 = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
                    LocalDateTime startTime2 = LocalDateTime.of(LocalDate.now().minusDays(7L), LocalTime.MIN);
                    //查询近7日得分：稽核评分相加/有稽核的天数
                    Double sumDeductionInLast7Days = projectCheckStandardScoreMapper.sumStandardDeduction(projectId, checkTableId, checkStandardScoreVo.getCheckStandardId(), startTime2, endTime2);
                    if(sumDeductionInLast7Days != null){
                        // 统计一段时间内项目的稽核表稽核天数
                        long last7DaysCheckDays = countProjectCheckDays(projectId, checkTableId, startTime2, endTime2);
                        if(last7DaysCheckDays > 0){
                            checkStandardScoreVo.setAvgScoreInLast7Days(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumDeductionInLast7Days, new BigDecimal(last7DaysCheckDays), 1)));
                        }
                    }
                    checkStandardScoreVo.setLast7DaysDeduction(sumDeductionInLast7Days);
                    checkStandardScoreVo.setModuleDeduction(projectCheckStandardScoreMapper.sumModuleDeduction(projectId, checkTableId, checkStandardScoreVo.getCheckModuleId(), startTime, endTime));
                    checkStandardScoreVoList.add(checkStandardScoreVo);
                }
                checkStandardScoreStatistic.setCheckStandardScoreVoList(checkStandardScoreVoList);
                double score = calculateProjectTotalScore(projectId, checkTableId, startTime, endTime, checkStandardScoreDtoList);
                checkStandardScoreStatistic.setScore(score);
            }
            return checkStandardScoreStatistic;
        }else if("7".equals(range) || "30".equals(range)){
            // 查询所有三级指标
            return queryAllCheckStandardScoreStatistic(projectId, checkTableId, checkModuleId, startTime, endTime);
        }else {
            throw new CustomException("统计范围参数不正确");
        }
    }


    /**
     * 查询所有三级指标
     * @param projectId
     * @param checkTableId
     * @param checkModuleId
     * @param startTime
     * @param endTime
     * @return
     */
    private CheckStandardScoreStatistic queryAllCheckStandardScoreStatistic(String projectId, String checkTableId, String checkModuleId, LocalDateTime startTime, LocalDateTime endTime) {
        CheckStandardScoreStatistic checkStandardScoreStatistic = new CheckStandardScoreStatistic();
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(projectId, checkTableId);
        if(projectCheckTable == null){
            throw new CustomException("【参数错误】未找到项目与稽核标准的绑定关系");
        }
        checkStandardScoreStatistic.setPassingScore(projectCheckTable.getPassingScore());
        List<CheckStandardScoreVo> checkStandardScoreVoList = new ArrayList<>();
        List<ProjectCheckStandardScoreDto> allCheckStandardScoreDtoList = new ArrayList<>();
        // 有过扣分的标准对应的指标的扣分，用来填充相同指标的扣分值
        Map<String, String> criteriaDeductionMap = new HashMap<>();
        //查询所有稽核标准
        LambdaQueryWrapperX<CheckStandard> queryWrapper = new LambdaQueryWrapperX<CheckStandard>()
                .eqIfPresent(CheckStandard::getCheckModuleId, checkModuleId)
                .eqIfPresent(CheckStandard::getCheckTableId, checkTableId);
        List<CheckStandard> checkStandardList = iCheckStandardService.list(queryWrapper);
        for(CheckStandard checkStandard : checkStandardList){
            CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
            queryCondition.setProjectId(projectId);
            queryCondition.setCheckTableId(checkTableId);
            queryCondition.setCheckModuleId(checkModuleId);
            queryCondition.setStartTime(startTime);
            queryCondition.setEndTime(endTime);
            queryCondition.setCheckStandardId(checkStandard.getCheckStandardId());
            queryCondition.setOrderBy("d.sort_num asc");
            // 查询出标准的扣分明细
            List<ProjectCheckStandardScoreDto> checkStandardScoreDtoList = projectCheckStandardScoreMapper.queryStandardScore(queryCondition);

            if(CollectionUtil.isNotEmpty(checkStandardScoreDtoList)){
                allCheckStandardScoreDtoList.addAll(checkStandardScoreDtoList);
                // 排序
                LinkedHashMap<String, List<ProjectCheckStandardScoreDto>> checkStandardScoreMap = checkStandardScoreDtoList.stream()
                        .sorted(Comparator.comparing(ProjectCheckStandardScoreDto::getStandardSortNum))
                        .collect(Collectors.groupingBy(ProjectCheckStandardScoreDto::getCheckStandardId, LinkedHashMap::new, Collectors.toList()));
                for (Map.Entry<String, List<ProjectCheckStandardScoreDto>> entry : checkStandardScoreMap.entrySet()) {
                    List<ProjectCheckStandardScoreDto> checkStandardScoreList = entry.getValue();
                    ProjectCheckStandardScoreDto checkStandardScoreDto = checkStandardScoreList.get(0);
                    CheckStandardScoreVo checkStandardScoreVo = BeanCopyUtil.copyProperties(checkStandardScoreDto, CheckStandardScoreVo.class);

                    double sumCriteriaDeduction = projectCheckStandardScoreMapper.sumCriteriaDeduction(projectId, checkTableId, checkStandardScoreDto.getCheckCriteriaId(), startTime, endTime);
                    double sumStandardDeduction = checkStandardScoreList.stream().mapToDouble(ProjectCheckStandardScoreDto::getDeduction).sum();
                    // 统计区间内有稽核的天数
                    long checkDays = countProjectCheckDays(projectId, checkTableId, startTime, endTime);
                    if(checkDays > 0){
                        checkStandardScoreVo.setDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumStandardDeduction, new BigDecimal(checkDays), 1)));
                        checkStandardScoreVo.setCriteriaDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumCriteriaDeduction, new BigDecimal(checkDays), 1)));
                        criteriaDeductionMap.put(checkStandardScoreDto.getCheckCriteriaId(), checkStandardScoreVo.getCriteriaDeduction());
                    }
                    LocalDateTime endTime2 = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
                    LocalDateTime startTime2 = LocalDateTime.of(LocalDate.now().minusDays(7L), LocalTime.MIN);
                    //查询近7日得分：稽核评分相加/有稽核的天数
                    Double sumDeductionInLast7Days = projectCheckStandardScoreMapper.sumStandardDeduction(projectId, checkTableId, checkStandardScoreVo.getCheckStandardId(), startTime2, endTime2);
                    if(sumDeductionInLast7Days != null){
                        // 统计一段时间内项目的稽核表稽核天数
                        long last7DaysCheckDays = countProjectCheckDays(projectId, checkTableId, startTime2, endTime2);
                        if(last7DaysCheckDays > 0){
                            checkStandardScoreVo.setAvgScoreInLast7Days(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumDeductionInLast7Days, new BigDecimal(last7DaysCheckDays), 1)));
                        }
                    }
                    checkStandardScoreVo.setLast7DaysDeduction(sumDeductionInLast7Days);
                    checkStandardScoreVo.setModuleDeduction(projectCheckStandardScoreMapper.sumModuleDeduction(projectId, checkTableId, checkStandardScoreVo.getCheckModuleId(), startTime, endTime));

                    checkStandardScoreVoList.add(checkStandardScoreVo);
                }
            }else {
                CheckStandardScoreVo checkStandardScoreVo = new CheckStandardScoreVo();
                checkStandardScoreVo.setCheckModuleId(checkStandard.getCheckModuleId());
                CheckModule checkModule = iCheckModuleService.getById(checkStandard.getCheckModuleId());
                if(checkModule != null){
                    checkStandardScoreVo.setModuleName(checkModule.getModuleName());
                }
                CheckCriteria checkCriteria = iCheckCriteriaService.getById(checkStandard.getCheckCriteriaId());
                String criteriaDeduction = "";
                if(checkCriteria != null){
                    checkStandardScoreVo.setCheckCriteriaId(checkCriteria.getCheckCriteriaId());
                    checkStandardScoreVo.setCriteriaName(checkCriteria.getCriteriaName());
                    String criteriaDeductionHis = criteriaDeductionMap.get(checkCriteria.getCheckCriteriaId());
                    if(CharSequenceUtil.isNotBlank(criteriaDeductionHis)){
                        criteriaDeduction = criteriaDeductionHis;
                    }
                }
                checkStandardScoreVo.setCriteriaDeduction(criteriaDeduction);
                checkStandardScoreVo.setModuleDeduction(null);
                checkStandardScoreVo.setCheckStandardId(checkStandard.getCheckStandardId());
                checkStandardScoreVo.setStandardName(checkStandard.getStandardName());
                checkStandardScoreVo.setDeductionItem(checkStandard.getDeductionItem());
                checkStandardScoreVo.setScore(checkStandard.getScore());
                checkStandardScoreVo.setDeduction("");
                checkStandardScoreVo.setLast7DaysDeduction(null);
                checkStandardScoreVo.setAvgScoreInLast7Days("");

                checkStandardScoreVoList.add(checkStandardScoreVo);
            }
            checkStandardScoreStatistic.setCheckStandardScoreVoList(checkStandardScoreVoList.stream().sorted(Comparator.comparing(CheckStandardScoreVo::getCheckCriteriaId)).collect(Collectors.toList()));
        }
        //计算项目总得分
        double score = calculateProjectTotalScore(projectId, checkTableId, startTime, endTime, allCheckStandardScoreDtoList);
        checkStandardScoreStatistic.setScore(score);
        return checkStandardScoreStatistic;
    }



    /**
     * 查询一段时间范围内稽核补充记录
     * @param projectId
     * @param checkTableId
     * @param range
     * @return
     */
    public List<CheckRecordVo> queryCheckRecordVo(String projectId, String checkTableId, String range) {
        List<CheckRecordVo> checkRecordVoList = new ArrayList<>();
        DateTimeRange dateTimeRange = getDateTimeRange(range);
        List<ProjectCheckRecord> list = iProjectCheckRecordService.queryProjectCheckRecord(projectId, checkTableId, dateTimeRange.startTime, dateTimeRange.endTime);
        if(CollectionUtil.isNotEmpty(list)){
            List<String> appUserIdList = list.stream().map(ProjectCheckRecord::getCreateBy).collect(Collectors.toList());
            Map<String, AppUser> appUserMap = iAppUserService.queryAppUserMap(appUserIdList);
            for (ProjectCheckRecord projectCheckRecord : list) {
                CheckRecordVo checkRecordVo = new CheckRecordVo();
                checkRecordVo.setRemark(projectCheckRecord.getRemark());
                checkRecordVo.setCreateTime(projectCheckRecord.getCreateTime());
                AppUser appUser = appUserMap.get(projectCheckRecord.getCreateBy());
                if(appUser != null){
                    checkRecordVo.setCreatorRealName(appUser.getRealName());
                }
                checkRecordVo.setImagePathList(queryCheckRecordImages(projectCheckRecord.getProjectCheckRecordId()));
                checkRecordVoList.add(checkRecordVo);
            }
        }
        return checkRecordVoList.stream().filter(t -> StrUtil.isNotBlank(t.getRemark()) || CollectionUtil.isNotEmpty(t.getImagePathList())).collect(Collectors.toList());
    }



    /**
     * 查询一定时间范围内有过评分的稽核模块列表
     * @param projectId
     * @param checkTableId
     * @param range
     * @return
     */
    public List<CheckModuleLite> queryCheckModuleLiteList(String projectId, String checkTableId, String range) {
        if("today".equals(range)){
            DateTimeRange dateTimeRange = getDateTimeRange(range);
            // 从数据库中查询出项目稽核表的打分记录
            CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
            queryCondition.setProjectId(projectId);
            queryCondition.setCheckTableId(checkTableId);
            queryCondition.setStartTime(dateTimeRange.startTime);
            queryCondition.setEndTime(dateTimeRange.endTime);
            List<ProjectCheckStandardScoreDto> projectCheckStandardScores = projectCheckStandardScoreMapper.queryValidStandardScore(queryCondition);
            if(CollectionUtil.isNotEmpty(projectCheckStandardScores)){
                // 将打分记录转CheckItem，方便转成 模块（module）-> 指标（criteria）-> 标准（standard）结构
                List<CheckItem> checkItemList = BeanCopyUtil.copyList(projectCheckStandardScores, CheckItem.class);
                List<CheckModuleDetail> checkModuleDetailList = convert2CheckModuleDetailList(checkItemList);
                List<CheckModule> checkModuleList = checkModuleDetailList.stream().map(CheckModuleDetail::getCheckModule)
                        .sorted(Comparator.comparing(CheckModule::getSortNum)).collect(Collectors.toList());
                return BeanCopyUtil.copyList(checkModuleList, CheckModuleLite.class);
            }
        }else if("7".equals(range) || "30".equals(range)){
            // 查所有3级指标
            return queryAllCheckModuleLiteList(projectId, checkTableId);
        }else {
            throw new CustomException("统计范围参数不正确");
        }
        return null;
    }

    private List<CheckModuleLite> queryAllCheckModuleLiteList(String projectId, String checkTableId) {
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(projectId, checkTableId);
        if(projectCheckTable == null){
            throw new CustomException("参数值不正确");
        }
        LambdaQueryWrapperX<CheckModule> queryWrapper = new LambdaQueryWrapperX<CheckModule>()
                .eq(CheckModule::getCheckTableId, checkTableId);
        return BeanCopyUtil.copyList(iCheckModuleService.list(queryWrapper), CheckModuleLite.class);

    }


    /**
     * 查询某一时段标准稽核详情列表和图片列表
     * @param projectId
     * @param checkTableId
     * @param checkStandardId
     * @param range
     * @return
     */
    public CheckStandardStatisticDetail queryCheckStandardStatisticDetail(String projectId,
                                                                          String checkTableId,
                                                                          String checkStandardId,
                                                                          String range) {
        ProjectCheckTable projectCheckTable = iProjectCheckTableService.queryProjectCheckTable(projectId, checkTableId);
        if(projectCheckTable == null){
            throw new CustomException("参数值不正确");
        }
        CheckStandard checkStandard = iCheckStandardService.getById(checkStandardId);
        CheckCriteria checkCriteria = iCheckCriteriaService.getById(checkStandard.getCheckCriteriaId());
        CheckModule checkModule = iCheckModuleService.getById(checkStandard.getCheckModuleId());

        DateTimeRange dateTimeRange = getDateTimeRange(range);
        LocalDateTime startTime = dateTimeRange.startTime;
        LocalDateTime endTime = dateTimeRange.endTime;
        // 统计一段时间内项目的稽核表稽核表稽核天数
        long checkDays = countProjectCheckDays(projectId, checkTableId, startTime, endTime);

        CheckStandardStatisticDetail checkStandardStatisticDetail = new CheckStandardStatisticDetail();
        checkStandardStatisticDetail.setCheckModuleName(checkModule.getModuleName());
        checkStandardStatisticDetail.setModuleScore(checkModule.getScore());
        Double sumModuleDeduction = projectCheckStandardScoreMapper.sumModuleDeduction(projectId, checkTableId, checkStandard.getCheckModuleId(), startTime, endTime);
        if(checkDays > 0 && sumModuleDeduction != null){
            checkStandardStatisticDetail.setModuleDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumModuleDeduction, new BigDecimal(checkDays), 1)));
        }
        checkStandardStatisticDetail.setCriteriaName(checkCriteria.getCriteriaName());
        checkStandardStatisticDetail.setCriteriaScore(checkCriteria.getScore());
        Double sumCriteriaDeduction = projectCheckStandardScoreMapper.sumCriteriaDeduction(projectId, checkTableId, checkStandard.getCheckCriteriaId(), startTime, endTime);
        if(checkDays > 0 && sumCriteriaDeduction != null){
            checkStandardStatisticDetail.setCriteriaDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumCriteriaDeduction, new BigDecimal(checkDays), 1)));
        }
        checkStandardStatisticDetail.setStandardName(checkStandard.getStandardName());
        checkStandardStatisticDetail.setDeductionItem(checkStandard.getDeductionItem());
        checkStandardStatisticDetail.setScore(checkStandard.getScore());
        Double sumStandardDeduction = projectCheckStandardScoreMapper.sumStandardDeduction(projectId, checkTableId, checkStandardId, startTime, endTime);
        if(checkDays > 0 && sumStandardDeduction != null){
            checkStandardStatisticDetail.setDeduction(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumStandardDeduction, new BigDecimal(checkDays), 1)));
        }

        LocalDateTime endTime2 = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
        LocalDateTime startTime2 = LocalDateTime.of(LocalDate.now().minusDays(7L), LocalTime.MIN);
        //查询近7日得分：稽核标准评分相加/稽核表稽核天数
        Double sumStandardDeductionInLast7Days = projectCheckStandardScoreMapper.sumStandardDeduction(projectId, checkTableId, checkStandardId, startTime2, endTime2);
        checkStandardStatisticDetail.setLast7DaysDeduction(sumStandardDeductionInLast7Days);
        if(sumStandardDeductionInLast7Days != null){
            // 统计一段时间内项目的稽核表稽核天数
            long last7DayCheckDays = countProjectCheckDays(projectId, checkTableId, startTime2, endTime2);
            if(last7DayCheckDays > 0){
                checkStandardStatisticDetail.setAvgScoreInLast7Days(NumberUtil.decimalFormat("0.0", NumberUtil.div(sumStandardDeductionInLast7Days, new BigDecimal(last7DayCheckDays), 1)));
            }
        }
        CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
        queryCondition.setProjectId(projectId);
        queryCondition.setCheckTableId(checkTableId);
        queryCondition.setCheckStandardId(checkStandardId);
        queryCondition.setStartTime(startTime);
        queryCondition.setEndTime(endTime);
        queryCondition.setOrderBy("abs(deduction) desc");

        List<ProjectCheckStandardScoreDto> projectCheckStandardScoreDtoList = projectCheckStandardScoreMapper.queryStandardScore(queryCondition);
        if(CollectionUtil.isNotEmpty(projectCheckStandardScoreDtoList)){
            List<CheckStandardStatisticDetail.CheckStandardScoreImageVo> checkStandardScoreImageVoList = new ArrayList<>(projectCheckStandardScoreDtoList.size());
            for(ProjectCheckStandardScoreDto  checkStandardScoreDto : projectCheckStandardScoreDtoList){
                CheckStandardStatisticDetail.CheckStandardScoreImageVo checkStandardScoreImageVo = new CheckStandardStatisticDetail.CheckStandardScoreImageVo();
                AppUser checkUser = iAppUserService.getById(checkStandardScoreDto.getCreateBy());
                checkStandardScoreImageVo.setCheckTime(checkStandardScoreDto.getCheckTime());
                checkStandardScoreImageVo.setRemark(checkStandardScoreDto.getRemark());
                checkStandardScoreImageVo.setDeduction(checkStandardScoreDto.getDeduction());
                checkStandardScoreImageVo.setCheckerRealName(checkUser.getRealName());

                List<String> imagePathList = queryProjectCheckStandardScoreImageList(checkStandardScoreDto.getProjectCheckStandardScoreId());
                checkStandardScoreImageVo.setImagePathList(imagePathList);
                checkStandardScoreImageVoList.add(checkStandardScoreImageVo);
            }
            checkStandardStatisticDetail.setCheckStandardScoreImageVoList(checkStandardScoreImageVoList);
        }
        return checkStandardStatisticDetail;
    }

    /**
     * 查询一段时间范围稽核表历史得分记录
     * @param projectId
     * @param checkTableId
     * @param startDate
     * @param endDate
     * @return
     */
    public List<DeductionDatum> queryDeductionDatum(String projectId, String checkTableId, LocalDate startDate, LocalDate endDate) {
        // 计算总得分=稽核表中所有扣分模块设置的分值 + 所有标准的得分（正数表示有加分，负数表示有扣分）
        // 转换为LocalDate类型
        LocalDate currentDate = startDate;
        List<DeductionDatum> deductionDatumList = new ArrayList<>();
        // 查询稽核表中所有扣分模块设置的分值
        while (!currentDate.isAfter(endDate)) {
            LocalDateTime startTime = LocalDateTime.of(currentDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(currentDate, LocalTime.MAX);

            CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
            queryCondition.setProjectId(projectId);
            queryCondition.setCheckTableId(checkTableId);
            queryCondition.setStartTime(startTime);
            queryCondition.setEndTime(endTime);
            // 查询出标准的扣分明细
            List<ProjectCheckStandardScoreDto> checkStandardScoreDtoList = projectCheckStandardScoreMapper.queryStandardScore(queryCondition);
            double score = calculateProjectTotalScore(projectId, checkTableId, startTime, endTime, checkStandardScoreDtoList);
            DeductionDatum deductionDatum = new DeductionDatum();
            deductionDatum.setDate(currentDate);
            deductionDatum.setDeduction(score);
            deductionDatumList.add(deductionDatum);
            // 往后推一天
            currentDate = currentDate.plusDays(1);
        }
        return deductionDatumList;
    }



    private static class DateTimeRange {
        public final LocalDateTime startTime;
        public final LocalDateTime endTime;

        public DateTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
            this.startTime = startTime;
            this.endTime = endTime;
        }
    }

    private DateTimeRange getDateTimeRange(String range) {
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        if("7".equals(range)){
            endTime = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
            startTime = LocalDateTime.of(LocalDate.now().minusDays(7L), LocalTime.MIN);
        }
        if("30".equals(range)){
            endTime = LocalDateTime.of(LocalDate.now().minusDays(1L), LocalTime.MAX);
            startTime = LocalDateTime.of(LocalDate.now().minusDays(30L), LocalTime.MIN);
        }
        return new DateTimeRange(startTime, endTime);
    }

    /**
     * 计算项目稽核平均得分。平均得分=总得分/稽核天数
     * 总得分= 稽核表的所有扣分模块设置的分值 * 有过稽核天数天数 + 区间内所有标准得分（有正有负）
     * @param projectId
     * @param checkTableId
     * @param startTime
     * @param endTime
     * @param checkStandardScoreDtoList
     * @return
     */
    private double calculateProjectTotalScore(String projectId, String checkTableId, LocalDateTime startTime, LocalDateTime endTime, List<ProjectCheckStandardScoreDto> checkStandardScoreDtoList) {
        // 稽核表的所有扣分模块设置的分值
        double minusModuleScoreInCheckTable = queryTotalMinusModuleScoreInCheckTable(checkTableId);
        // 有过稽核天数
        long days = countProjectCheckDays(projectId, checkTableId, startTime, endTime);
        // 稽核表的所有扣分模块设置的分值 * 有过稽核天数
        double allModuleScore =  minusModuleScoreInCheckTable * days;
        // 区间内所有标准得分(有正有负)
        double totalStandardDeduction = checkStandardScoreDtoList.stream().mapToDouble(ProjectCheckStandardScoreDto::getDeduction).sum();
        // 总得分
        double totalScore = allModuleScore + totalStandardDeduction;
        // 统计一段时间内项目的稽核表稽核次数
//        long checkCount = countProjectCheckRecord(projectId, checkTableId, startTime, endTime);
//        if(checkCount > 0){
//            // 平均得分：总得分 / 区间内稽核次数
//            return NumberUtil.div(totalScore, checkCount, 1);
//        } else {
//            return 0.0D;
//        }
        if(days > 0){
            // 平均得分：总得分 / 区间内稽核天数
            return NumberUtil.div(totalScore, days, 1);
        }else {
            return 0.0D;
        }
    }





    /**
     * 查询一段时间内稽核的天数
     * @param projectId
     * @param checkTableId
     * @param startTime
     * @param endTime
     * @return
     */
    private long countProjectCheckDays(String projectId, String checkTableId, LocalDateTime startTime, LocalDateTime endTime) {
        Set<LocalDate> createDateSet = new HashSet<>();
        List<ProjectCheckRecord> checkRecordList = iProjectCheckRecordService.queryProjectCheckRecord(projectId, checkTableId, startTime, endTime);
        if(CollectionUtil.isNotEmpty(checkRecordList)){
            List<Date> createTimeList = checkRecordList.stream().map(ProjectCheckRecord::getCreateTime).collect(Collectors.toList());
            for(Date createTime : createTimeList){
                LocalDate createDate = DateUtil.toLocalDateTime(createTime).toLocalDate();
                createDateSet.add(createDate);
            }
        }
        return createDateSet.size();
    }



    /**
     * 查询各个层级的允许填写的上限分数
     * @param checkModule
     * @param checkCriteria
     * @param checkStandard
     * @param deduction
     * @return
     */
    private ThresholdScore getThresholdScore(CheckModule checkModule,
                                             CheckCriteria checkCriteria,
                                             CheckStandard checkStandard,
                                             Double deduction) {
        int isAllowAddScore = checkModule.getIsAllowAddScore();
        if(Constants.NO == isAllowAddScore && deduction > 0){
            throw new CustomException("该模块不允许加分");
        }
        if(Constants.YES == isAllowAddScore && deduction < 0){
            throw new CustomException("该模块不允许减分");
        }
        // 管理端设置的标准分值，正值
        Double standardScore = checkStandard.getScore();
        Double criteriaScore = checkCriteria.getScore();
        Double checkModuleScore = checkModule.getScore();
        if(standardScore == null && criteriaScore != null){
            // 如果标准分值为空，指标分值不为空，则该标准允许的分值= 指标的分值- 指标下所有标准的分值和
            List<CheckStandard> checkStandardList = queryCheckStandardList(checkCriteria.getCheckCriteriaId());
            double standScoreInCriteria = checkStandardList.stream().filter(t -> t.getScore() != null).mapToDouble(CheckStandard::getScore).sum();
            standardScore = criteriaScore - standScoreInCriteria;
        }else if(standardScore == null && criteriaScore == null){
            // 如果标准分值和指标分值都为空，则该标准允许的分值 = 模块的分值- 模块下所有标准的分值和
            List<CheckStandard> checkStandardList = queryCheckStandardListUnderModule(checkModule.getCheckModuleId());
            double standScoreInModule = checkStandardList.stream().filter(t -> t.getScore() != null).mapToDouble(CheckStandard::getScore).sum();
            standardScore = checkModuleScore - standScoreInModule;
        }
        if(criteriaScore == null && checkModuleScore != null){
            // 如果指标分值为空，则该指标允许的分值 = 模块的分值- 模块下所有指标的分值和
            List<CheckCriteria> checkCriteriaList = queryCheckCriteriaList(checkModule.getCheckModuleId());
            double criteriaScoreInModule = checkCriteriaList.stream().filter(t -> t.getScore() != null).mapToDouble(CheckCriteria::getScore).sum();
            criteriaScore = checkModuleScore - criteriaScoreInModule;
        }
        return new ThresholdScore(standardScore, criteriaScore, checkModuleScore);
    }



    private static class ThresholdScore {
        public final Double standardScore;
        public final Double criteriaScore;
        public final Double checkModuleScore;

        public ThresholdScore(Double standardScore, Double criteriaScore, Double checkModuleScore) {
            this.standardScore = standardScore;
            this.criteriaScore = criteriaScore;
            this.checkModuleScore = checkModuleScore;
        }
    }


    /**
     * 判断前端传来的单个标准的得分值是否符合扣分规则的阈值
     *
     * @param deductionInDb 该标准今天所有已提交的标准的得分和
     * @param deduction 前端传来的单个标准的得分值
     * @param threshHoldScore 管理端设置的标准分值
     * @param errorMsg
     */
    private void validateDeduction(Double deductionInDb, Double deduction, Double threshHoldScore, String errorMsg){
        double totalDeduction = Math.abs(deduction);
        if(deductionInDb != null){
            totalDeduction = Math.abs(deductionInDb) + Math.abs(deduction);
        }
        if(threshHoldScore != null && threshHoldScore > 0
                && totalDeduction > threshHoldScore){
            throw new CustomException(errorMsg);
        }
    }

    /**
     * 判断前端传来的单个标准的得分值是否符合扣分规则的阈值
     *
     * @param deduction 前端传来的单个标准的得分值
     * @param threshHoldScore 管理端设置的标准分值
     * @param errorMsg
     */
    private void validateDeduction(Double deduction, Double threshHoldScore, String errorMsg){
        double totalDeduction = Math.abs(deduction);
        if(threshHoldScore != null && threshHoldScore > 0
                && totalDeduction > threshHoldScore){
            throw new CustomException(errorMsg);
        }
    }



    /**
     * 查询某一次临时稽核记录中，某个标准今天所有已提交的得分总和
     * @param tempProjectCheckRecordId
     * @param checkStandardId
     * @return
     */
    private Double sumTodayTempStandardDeduction(String tempProjectCheckRecordId, String checkStandardId) {
        LambdaQueryWrapper<TempCheckItem> queryWrapper = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempProjectCheckRecordId)
                .eq(TempCheckItem::getCheckStandardId, checkStandardId)
                .between(TempCheckItem::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<TempCheckItem> list = iTempCheckItemService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(TempCheckItem::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 正式提交时，查询某一次稽核记录中，某个标准今天所有已提交的得分总和
     * @param projectCheckTableId
     * @param checkStandardId
     * @return
     */
    private Double sumTodayStandardDeduction(String projectCheckTableId, String checkStandardId) {
        LambdaQueryWrapper<ProjectCheckStandardScore> queryWrapper = new LambdaQueryWrapper<ProjectCheckStandardScore>()
                .eq(ProjectCheckStandardScore::getProjectCheckTableId, projectCheckTableId)
                .eq(ProjectCheckStandardScore::getCheckStandardId, checkStandardId)
                .between(ProjectCheckStandardScore::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<ProjectCheckStandardScore> list = iProjectCheckStandardScoreService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(ProjectCheckStandardScore::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 查询某一次临时稽核记录中，某个模块id下，今天所有已提交的标准的得分总和
     * @param tempProjectCheckRecordId
     * @param checkModuleId
     * @return
     */
    private Double sumTodayTempStandardDeductionUnderModule(String tempProjectCheckRecordId, String checkModuleId) {
        LambdaQueryWrapper<TempCheckItem> queryWrapper = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempProjectCheckRecordId)
                .eq(TempCheckItem::getCheckModuleId, checkModuleId)
                .between(TempCheckItem::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<TempCheckItem> list = iTempCheckItemService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(TempCheckItem::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 正式提交时，查询某一次稽核记录中，某个模块id下，今天所有已提交的标准的得分总和
     * @param projectCheckTableId
     * @param checkModuleId
     * @return
     */
    private Double sumTodayStandardDeductionUnderModule(String projectCheckTableId, String checkModuleId) {
        LambdaQueryWrapper<ProjectCheckStandardScore> queryWrapper = new LambdaQueryWrapper<ProjectCheckStandardScore>()
                .eq(ProjectCheckStandardScore::getProjectCheckTableId, projectCheckTableId)
                .eq(ProjectCheckStandardScore::getCheckModuleId, checkModuleId)
                .between(ProjectCheckStandardScore::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<ProjectCheckStandardScore> list = iProjectCheckStandardScoreService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(ProjectCheckStandardScore::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 查询某一次临时稽核记录中，某个指标id下，今天所有已提交的标准的得分总和
     * @param tempProjectCheckRecordId
     * @param checkCriteriaId
     * @return
     */
    private Double sumTodayTempStandardDeductionUnderCriteria(String tempProjectCheckRecordId, String checkCriteriaId) {
        LambdaQueryWrapper<TempCheckItem> queryWrapper = new LambdaQueryWrapper<TempCheckItem>()
                .eq(TempCheckItem::getTempProjectCheckRecordId, tempProjectCheckRecordId)
                .eq(TempCheckItem::getCheckCriteriaId, checkCriteriaId)
                .between(TempCheckItem::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<TempCheckItem> list = iTempCheckItemService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(TempCheckItem::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 正式提交时，查询某一次稽核记录中，某个指标id下，今天所有已提交的标准的得分总和
     * @param tempProjectCheckRecordId
     * @param checkCriteriaId
     * @return
     */
    private Double sumTodayStandardDeductionUnderCriteria(String tempProjectCheckRecordId, String checkCriteriaId) {
        LambdaQueryWrapper<ProjectCheckStandardScore> queryWrapper = new LambdaQueryWrapper<ProjectCheckStandardScore>()
                .eq(ProjectCheckStandardScore::getProjectCheckTableId, tempProjectCheckRecordId)
                .eq(ProjectCheckStandardScore::getCheckCriteriaId, checkCriteriaId)
                .between(ProjectCheckStandardScore::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.now());
        List<ProjectCheckStandardScore> list = iProjectCheckStandardScoreService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().mapToDouble(ProjectCheckStandardScore::getDeduction).sum();
        }
        return 0D;
    }

    /**
     * 查询一段时间内稽核记录
     * @param projectId
     * @param checkTableId
     * @param startTime
     * @param endTime
     * @return
     */


    /**
     *  查询项目的稽核表所有的标准在一定时间范围内的得分记录
     * @param projectId
     * @param checkTableId
     * @return
     */
    private List<ProjectCheckStandardScore> queryProjectCheckStandardScoreList(String projectId, String checkTableId, LocalDateTime startTime, LocalDateTime endTime) {
        CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
        queryCondition.setProjectId(projectId);
        queryCondition.setCheckTableId(checkTableId);
        queryCondition.setStartTime(startTime);
        queryCondition.setEndTime(endTime);
        return queryProjectCheckStandardScoreList(queryCondition);
    }





    /**
     * 查询今天稽核记录
     * @param projectId
     * @param checkTableId
     * @return
     */
    private List<CheckTableDetailVo.CheckRecordVo> queryTodayCheckRecord(String projectId, String checkTableId) {
        List<CheckTableDetailVo.CheckRecordVo> checkRecordVoList = new ArrayList<>();
        LambdaQueryWrapper<ProjectCheckRecord> queryWrapper = new LambdaQueryWrapper<ProjectCheckRecord>()
                .eq(ProjectCheckRecord::getProjectId, projectId)
                .eq(ProjectCheckRecord::getCheckTableId, checkTableId)
                .between(ProjectCheckRecord::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.of(LocalDate.now(), LocalTime.MAX));
        List<ProjectCheckRecord> list = iProjectCheckRecordService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            for(ProjectCheckRecord projectCheckRecord : list){
                CheckTableDetailVo.CheckRecordVo checkRecordVo = new CheckTableDetailVo.CheckRecordVo();
                checkRecordVo.setRemark(projectCheckRecord.getRemark());
                checkRecordVo.setImagePathList(queryCheckRecordImages(projectCheckRecord.getProjectCheckRecordId()));
                checkRecordVoList.add(checkRecordVo);
            }

        }
        return checkRecordVoList;

    }

    /**
     * 统计一段时间内项目的稽核表稽核次数
     * @param projectId
     * @param checkTableId
     * @param startTime
     * @param endTime
     * @return
     */
    private long countProjectCheckRecord(String projectId, String checkTableId, LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<ProjectCheckRecord> queryWrapper = new LambdaQueryWrapper<ProjectCheckRecord>()
                .eq(ProjectCheckRecord::getProjectId, projectId)
                .eq(ProjectCheckRecord::getCheckTableId, checkTableId)
                .between(ProjectCheckRecord::getCreateTime, startTime, endTime);
        return iProjectCheckRecordService.count(queryWrapper);
    }


    /**
     * 查询稽核标准打分时提交的图片路径
     * @param projectCheckStandardScoreId
     * @return
     */
    private List<String> queryProjectCheckStandardScoreImageList(String projectCheckStandardScoreId) {
        LambdaQueryWrapper<ProjectCheckStandardScoreImage> queryWrapper = new LambdaQueryWrapper<ProjectCheckStandardScoreImage>()
                .eq(ProjectCheckStandardScoreImage::getProjectCheckStandardScoreId, projectCheckStandardScoreId);
        List<ProjectCheckStandardScoreImage> list = iProjectCheckStandardScoreImageService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().map(ProjectCheckStandardScoreImage::getImagePath).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 查询稽核记录中的图片
     * @param projectCheckRecordId
     * @return
     */
    private List<String> queryCheckRecordImages(String projectCheckRecordId) {
        LambdaQueryWrapper<ProjectCheckRecordImage> queryWrapper = new LambdaQueryWrapper<ProjectCheckRecordImage>()
                .eq(ProjectCheckRecordImage::getProjectCheckRecordId, projectCheckRecordId);
        List<ProjectCheckRecordImage> list = iProjectCheckRecordImageService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.stream().map(ProjectCheckRecordImage::getImagePath).collect(Collectors.toList());
        }
        return null;
    }


    private List<String> queryTempImageUrlList(String tempCheckItemId) {
        LambdaQueryWrapper<TempCheckItemImage> queryWrapper = new LambdaQueryWrapper<TempCheckItemImage>()
                .eq(TempCheckItemImage::getTempCheckItemId, tempCheckItemId);
        List<TempCheckItemImage> imageList = iTempCheckItemImageService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(imageList)){
            return imageList.stream().map(TempCheckItemImage::getImagePath).collect(Collectors.toList());
        }
        return null;
    }


    /**
     * 保存稽核标准的扣分值
     * @param checkForm
     * @param projectCheckRecord
     */
    private void saveProjectCheckStandardScore(CheckForm checkForm, ProjectCheckRecord projectCheckRecord) {
        List<CheckItem> checkItemList = checkForm.getCheckItemList();
        if(CollectionUtil.isNotEmpty(checkItemList)){
            for(CheckItem checkItem : checkItemList){
                CheckStandard checkStandard = iCheckStandardService.getById(checkItem.getCheckStandardId());

                String projectCheckStandardScoreId = IdWorker.getIdStr();
                ProjectCheckStandardScore checkStandardScore = new ProjectCheckStandardScore();
                checkStandardScore.setProjectCheckStandardScoreId(projectCheckStandardScoreId);
                checkStandardScore.setProjectCheckRecordId(projectCheckRecord.getProjectCheckRecordId());
                checkStandardScore.setProjectCheckTableId(projectCheckRecord.getProjectCheckTableId());
                checkStandardScore.setProjectId(checkForm.getProjectId());
                checkStandardScore.setCheckTableId(checkForm.getCheckTableId());
                checkStandardScore.setCheckModuleId(checkStandard.getCheckModuleId());
                checkStandardScore.setCheckCriteriaId(checkStandard.getCheckCriteriaId());
                checkStandardScore.setCheckStandardId(checkItem.getCheckStandardId());
                checkStandardScore.setDeduction(checkItem.getDeduction());
                checkStandardScore.setRemark(checkItem.getRemark());
                List<String> imagePathList = checkItem.getImagePathList();
                // 保存评分标准对应的图片
                if(CollectionUtil.isNotEmpty(imagePathList)){
                    checkStandardScore.setHasImageFlag(Constants.YES);
                    List<ProjectCheckStandardScoreImage> standardScoreImageList = new ArrayList<>();
                    for(String imageUrl : imagePathList){
                        ProjectCheckStandardScoreImage standardScoreImage = new ProjectCheckStandardScoreImage();
                        standardScoreImage.setProjectCheckStandardScoreId(projectCheckStandardScoreId);
                        standardScoreImage.setImagePath(imageUrl);
                        standardScoreImageList.add(standardScoreImage);
                    }
                    iProjectCheckStandardScoreImageService.saveBatch(standardScoreImageList);
                }
                iProjectCheckStandardScoreService.save(checkStandardScore);
            }
        }
    }


    /**
     * 保存项目稽核记录。即每稽核一次，保存一次记录
     * @param checkForm
     * @param projectCheckTableId
     * @return
     */
    private ProjectCheckRecord saveProjectCheckRecord(CheckForm checkForm, String projectCheckTableId) {
        ProjectCheckRecord projectCheckRecord = new ProjectCheckRecord();
        projectCheckRecord.setProjectCheckTableId(projectCheckTableId);
        projectCheckRecord.setProjectId(checkForm.getProjectId());
        projectCheckRecord.setCheckTableId(checkForm.getCheckTableId());
        projectCheckRecord.setRemark(checkForm.getRemark());
        iProjectCheckRecordService.save(projectCheckRecord);

        // 如果有图，保存项目稽核记录对应的图片
        if(CollectionUtil.isNotEmpty(checkForm.getImagePathList())){
            List<ProjectCheckRecordImage> projectCheckRecordImageList = new ArrayList<>();
            for(String imageUrl : checkForm.getImagePathList()){
                ProjectCheckRecordImage projectCheckRecordImage = new ProjectCheckRecordImage();
                projectCheckRecordImage.setImagePath(imageUrl);
                projectCheckRecordImage.setProjectCheckRecordId(projectCheckRecord.getProjectCheckRecordId());
                projectCheckRecordImageList.add(projectCheckRecordImage);
            }
            iProjectCheckRecordImageService.saveBatch(projectCheckRecordImageList);
        }
        return projectCheckRecord;
    }


    /**
     * 验证稽核标准中的扣分值是否合格
     * @param projectCheckTableId
     * @param checkModuleDetailList
     */
    private void validateCheckStandardDeduction(String projectCheckTableId, List<CheckModuleDetail> checkModuleDetailList) {
        if(CollectionUtil.isNotEmpty(checkModuleDetailList)){
            for(CheckModuleDetail checkModuleDetail : checkModuleDetailList){
                CheckModule checkModule = checkModuleDetail.getCheckModule();
                Integer isAllowAttach = checkModule.getIsAllowAttach();
                List<CheckCriteriaDetail> checkCriteriaDetailList = checkModuleDetail.getCheckCriteriaDetailList();

                if (CollectionUtil.isNotEmpty(checkCriteriaDetailList)){
                    for(CheckCriteriaDetail checkCriteriaDetail : checkCriteriaDetailList){
                        CheckCriteria checkCriteria = checkCriteriaDetail.getCheckCriteria();
                        List<CheckItem> checkItemList = checkCriteriaDetail.getCheckItemList();

                        if (CollectionUtil.isNotEmpty(checkItemList)){
                            for(CheckItem checkItem : checkItemList){
                                if(Constants.YES == isAllowAttach && CollectionUtil.isEmpty(checkItem.getImagePathList())){
                                    String errorMsg = checkModule.getModuleName() + "模块要求必传图片";
                                    throw new CustomException(errorMsg);
                                }
                                // 前端提交过来标准的得分值。可正可负
                                Double deduction = checkItem.getDeduction();
                                String checkStandardId = checkItem.getCheckStandardId();
                                //验证分值是否合规
                                CheckStandard checkStandard = iCheckStandardService.getById(checkStandardId);
                                // 验证前端提交的打分记录是否符合打分规则
                                validateSubmitCheckStandardDeduction(projectCheckTableId, checkModule, checkCriteria, checkStandard,  deduction);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 将打分标准按 模块（module）-》指标（criteria）-> 标准（standard）层次组装好，方便计算扣分值有没有超过总分值限制
     * @param checkStandardVoList
     * @return
     */
    private List<CheckModuleVo> convert2CheckModuleVoList(List<CheckStandardVo> checkStandardVoList){
        if(CollectionUtil.isNotEmpty(checkStandardVoList)){
            Map<CheckCriteria, List<CheckStandardVo>> checkCriteriaListHashMap = new LinkedHashMap<>();
            for(CheckStandardVo checkStandardVo : checkStandardVoList){
                String checkStandardId = checkStandardVo.getCheckStandardId();
                CheckStandard checkStandard = iCheckStandardService.getById(checkStandardId);
                String checkCriteriaId = checkStandard.getCheckCriteriaId();
                CheckCriteria checkCriteria = iCheckCriteriaService.getById(checkCriteriaId);

                if(CollectionUtil.isEmpty(checkCriteriaListHashMap.get(checkCriteria))){
                    checkCriteriaListHashMap.put(checkCriteria, new ArrayList<>());
                }
                checkCriteriaListHashMap.get(checkCriteria).add(checkStandardVo);
            }
            List<CheckCriteriaVo> checkCriteriaVoList = new ArrayList<>();
            for(Map.Entry<CheckCriteria, List<CheckStandardVo>> entry : checkCriteriaListHashMap.entrySet()){
                CheckCriteria checkCriteria = entry.getKey();
                List<CheckStandardVo> checkStandardVoList1 = entry.getValue();
                CheckCriteriaVo checkCriteriaVo = BeanCopyUtil.copyProperties(checkCriteria, CheckCriteriaVo.class);
                checkCriteriaVo.setCheckStandardVoList(checkStandardVoList1);
                checkCriteriaVoList.add(checkCriteriaVo);
            }
            Map<CheckModule, List<CheckCriteriaVo>> checkModuleListHashMap = new LinkedHashMap<>();
            for(CheckCriteriaVo checkCriteriaVo : checkCriteriaVoList){
                String checkModuleId = checkCriteriaVo.getCheckModuleId();
                CheckModule checkModule = iCheckModuleService.getById(checkModuleId);
                if(CollectionUtil.isEmpty(checkModuleListHashMap.get(checkModule))){
                    checkModuleListHashMap.put(checkModule, new ArrayList<>());
                }
                checkModuleListHashMap.get(checkModule).add(checkCriteriaVo);
            }

            List<CheckModuleVo> checkModuleVoList = new ArrayList<>();
            for(Map.Entry<CheckModule, List<CheckCriteriaVo>> entry : checkModuleListHashMap.entrySet()){
                CheckModule checkModule = entry.getKey();
                List<CheckCriteriaVo> checkCriteriaVoList1 = entry.getValue();
                CheckModuleVo checkModuleVo = BeanCopyUtil.copyProperties(checkModule, CheckModuleVo.class);
                checkModuleVo.setCheckCreteriaVoList(checkCriteriaVoList1);
                checkModuleVoList.add(checkModuleVo);
            }
            return checkModuleVoList;
        }
        return null;
    }


    /**
     * 将打分标准按 模块（module）-》指标（criteria）-> 标准（standard）层次组装好，方便计算扣分值有没有超过总分值限制
     * @param checkItemFormList
     * @return
     */
    private List<CheckModuleDetail> convert2CheckModuleDetailList(List<CheckItem> checkItemFormList) {
        if(CollectionUtil.isNotEmpty(checkItemFormList)){
            Map<CheckCriteria, List<CheckItem>> checkCriteriaListHashMap = new HashMap<>();
            for(CheckItem checkItem : checkItemFormList){
                String checkStandardId = checkItem.getCheckStandardId();
                CheckStandard checkStandard = iCheckStandardService.getById(checkStandardId);
                String checkCriteriaId = checkStandard.getCheckCriteriaId();
                CheckCriteria checkCriteria = iCheckCriteriaService.getById(checkCriteriaId);

                if(CollectionUtil.isEmpty(checkCriteriaListHashMap.get(checkCriteria))){
                    checkCriteriaListHashMap.put(checkCriteria, new ArrayList<>());
                }
                checkCriteriaListHashMap.get(checkCriteria).add(checkItem);
            }

            List<CheckCriteriaDetail> checkCriteriaDetailList = new ArrayList<>();
            for(Map.Entry<CheckCriteria, List<CheckItem>> entry : checkCriteriaListHashMap.entrySet()){
                CheckCriteria checkCriteria = entry.getKey();
                List<CheckItem> checkItemList = entry.getValue();
                checkCriteriaDetailList.add(new CheckCriteriaDetail(checkCriteria, checkItemList));
            }

            Map<CheckModule, List<CheckCriteriaDetail>> checkModuleListHashMap = new HashMap<>();
            for(CheckCriteriaDetail checkCriteriaDetail : checkCriteriaDetailList){
                String checkModuleId = checkCriteriaDetail.getCheckCriteria().getCheckModuleId();
                CheckModule checkModule = iCheckModuleService.getById(checkModuleId);
                if(CollectionUtil.isEmpty(checkModuleListHashMap.get(checkModule))){
                    checkModuleListHashMap.put(checkModule, new ArrayList<>());
                }
                checkModuleListHashMap.get(checkModule).add(checkCriteriaDetail);
            }

            List<CheckModuleDetail> checkModuleDetailList = new ArrayList<>();
            for(Map.Entry<CheckModule, List<CheckCriteriaDetail>> entry : checkModuleListHashMap.entrySet()){
                CheckModule checkModule = entry.getKey();
                List<CheckCriteriaDetail> criteriaDetailList = entry.getValue();
                checkModuleDetailList.add(new CheckModuleDetail(checkModule, criteriaDetailList));
            }
            return checkModuleDetailList;

        }
        return null;
    }



    @Data
    public static class CheckModuleDetail{
        private CheckModule checkModule;
        private List<CheckCriteriaDetail> checkCriteriaDetailList;

        public CheckModuleDetail(CheckModule checkModule, List<CheckCriteriaDetail> checkCriteriaDetailList) {
            this.checkModule = checkModule;
            this.checkCriteriaDetailList = checkCriteriaDetailList;
        }
    }



    @Data
    public static class CheckCriteriaDetail{

        private CheckCriteria checkCriteria;

        private List<CheckItem> checkItemList;

        public CheckCriteriaDetail(CheckCriteria checkCriteria, List<CheckItem> checkItemList){
            this.checkCriteria = checkCriteria;
            this.checkItemList = checkItemList;
        }

    }






    /**
     * 查询标准今天的得分
     * @param projectId
     * @param checkTableId
     * @param checkStandardId
     * @return
     */
    private ProjectCheckStandardScore queryTodayProjectCheckStandardScore(String projectId, String checkTableId, String checkStandardId) {
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.now();
        CheckStandardScoreQueryCondition queryCondition = new CheckStandardScoreQueryCondition();
        queryCondition.setProjectId(projectId);
        queryCondition.setCheckTableId(checkTableId);
        queryCondition.setCheckStandardId(checkStandardId);
        queryCondition.setStartTime(startTime);
        queryCondition.setEndTime(endTime);
        List<ProjectCheckStandardScore> projectCheckStandardScores = queryProjectCheckStandardScoreList(queryCondition);
        if(CollectionUtil.isNotEmpty(projectCheckStandardScores)){
            return projectCheckStandardScores.get(0);
        }
        return null;
    }

    /**
     * 多条件查询项目稽核表的标准评分记录
     * @param queryCondition
     * @return
     */
    private List<ProjectCheckStandardScore> queryProjectCheckStandardScoreList(CheckStandardScoreQueryCondition queryCondition){
        LambdaQueryWrapper<ProjectCheckStandardScore> queryWrapper = new LambdaQueryWrapperX<ProjectCheckStandardScore>()
                .eq(ProjectCheckStandardScore::getProjectId, queryCondition.getProjectId())
                .eq(ProjectCheckStandardScore::getCheckTableId, queryCondition.getCheckTableId())
                .eqIfPresent(ProjectCheckStandardScore::getCheckModuleId, queryCondition.getCheckModuleId())
                .eqIfPresent(ProjectCheckStandardScore::getCheckStandardId, queryCondition.getCheckStandardId())
                .betweenIfPresent(ProjectCheckStandardScore::getCreateTime, queryCondition.getStartTime(), queryCondition.getEndTime())
                .orderByDesc(ProjectCheckStandardScore::getCreateTime);
        return iProjectCheckStandardScoreService.list(queryWrapper);
    }




    /**
     * 统计一定时间范围内的稽核次数
     * @param queryStartTime
     * @param queryEndTime
     * @param projectId
     * @param checkTableId
     * @return
     */
    private Long queryPeriodCheckCount(LocalDateTime queryStartTime, LocalDateTime queryEndTime, String projectId, String checkTableId) {
        LambdaQueryWrapper<ProjectCheckRecord> queryWrapper = new LambdaQueryWrapper<ProjectCheckRecord>()
                .eq(ProjectCheckRecord::getProjectId, projectId)
                .eq(ProjectCheckRecord::getCheckTableId, checkTableId)
                .between(ProjectCheckRecord::getCreateTime, queryStartTime, queryEndTime);

        return iProjectCheckRecordService.count(queryWrapper);
    }


    /**
     * 根据稽核指标Id查询稽核标准
     * @param checkCriteriaId
     * @return
     */
    private List<CheckStandard> queryCheckStandardList(String checkCriteriaId) {
        LambdaQueryWrapper<CheckStandard> queryWrapper = new LambdaQueryWrapper<CheckStandard>()
                .eq(CheckStandard::getCheckCriteriaId, checkCriteriaId);
        return iCheckStandardService.list(queryWrapper);
    }


    /**
     * 根据模块Id查询稽核标准
     * @param checkModuleId
     * @return
     */
    private List<CheckStandard> queryCheckStandardListUnderModule(String checkModuleId) {
        LambdaQueryWrapper<CheckStandard> queryWrapper = new LambdaQueryWrapper<CheckStandard>()
                .eq(CheckStandard::getCheckStandardId, checkModuleId);
        return iCheckStandardService.list(queryWrapper);
    }

    /**
     * 根据标准名称模糊查询稽核标准
     * @param standardName
     * @return
     */
    private List<CheckStandard> queryCheckStandardListByStandardName(String standardName, String checkTableId){
        LambdaQueryWrapper<CheckStandard> queryWrapper = new LambdaQueryWrapperX<CheckStandard>()
                .eq(CheckStandard::getCheckTableId, checkTableId)
                .likeIfPresent(CheckStandard::getStandardName, standardName)
                .orderByAsc(CheckStandard::getSortNum);
        return iCheckStandardService.list(queryWrapper);
    }




    /**
     * 根据稽核模块Id查询稽核指标
     * @param checkModuleId
     * @return
     */
    private List<CheckCriteria> queryCheckCriteriaList(String checkModuleId) {
        LambdaQueryWrapper<CheckCriteria> queryWrapper = new LambdaQueryWrapper<CheckCriteria>()
                .eq(CheckCriteria::getCheckModuleId, checkModuleId);
        return iCheckCriteriaService.list(queryWrapper);
    }







}
